<html>
<head>
  <title>node.js 2.3——fs文件操作模块</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/607344 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <meta name="content-class" content="yinxiang.superNote"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 12pt;
    }
  </style>
</head>
<body>
<a name="17667"/>
<h1>node.js 2.3——fs文件操作模块</h1>

<div><span><h1>简介</h1><ul><li><div><a href="http://nodejs.cn/api/fs.html#fs_using_fs_writefile_with_file_descriptors" rev="en_rl_none">官方文档</a></div></li></ul><ul><li><div>需要调用 fs 模块</div></li><ul><li><div>var fs = require(&quot;fs&quot;);</div></li></ul><li><div>fs模块中所有的操作都有两种形式可供选择同步和异步。</div></li><ul><li><p>同步文件系统会阻塞程序的执行，也就是除非操作完毕，否则不会向下执行代码。</p></li><li><p>异步文件系统不会阻塞程序的执行，而是在操作完成时，通过回调函数将结果返回。</p></li><li><p>异步操作的方法，都需要给定callback函数</p></li><li><p>同步操作的方法名一般以Sync为后缀</p></li></ul><li><p>模式：</p></li></ul><table style="--en-fitwindow:false;border-left:1px solid #d9d9d9;border-top:1px solid #d9d9d9;border-collapse:collapse;width:533px;" width="533px"><colgroup><col style="width: 83px;"></col><col style="width: 450px;"></col></colgroup><tbody><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>r</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以读取模式打开文件。如果文件不存在抛出异常。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>r+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以读写模式打开文件。如果文件不存在抛出异常。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>rs</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以同步的方式读取文件。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>rs+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以同步的方式读取和写入文件。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>w</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以写入模式打开文件，如果文件不存在则创建。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>wx</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>类似 'w'，但是如果文件路径存在，则文件写入失败。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>w+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以读写模式打开文件，如果文件不存在则创建。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>wx+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>类似 'w+'， 但是如果文件路径存在，则文件读写失败。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>a</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以追加模式打开文件，如果文件不存在则创建。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>ax</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>类似 'a'， 但是如果文件路径存在，则文件追加失败。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>a+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>以读取追加模式打开文件，如果文件不存在则创建。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>ax+</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>类似 'a+'， 但是如果文件路径存在，则文件读取追加失败。</div></td></tr></tbody></table><p><br/></p><h1>同步操作</h1><ul><li><div>同步操作的方法名一般以Sync为后缀</div></li><li><div>打开文件：fs.openSync(path, flags[, mode])</div></li><ul><li><div>path 要打开文件的路径</div></li><li><div>flags 打开文件要做的操作的类型</div></li><ul><li><div>'w' ：可写的</div></li><li><div>'r'：只读的</div></li><li><div>'a'：追加</div></li></ul><li><div>mode 设置文件的操作权限，一般不传</div></li><li><div>返回值：该方法会返回一个文件的描述符作为结果，我们可以通过该描述符来对文件进行各种操作</div></li></ul><li><div>保存关闭文件：fs.closeSync(fd)</div></li><ul><li><div>fd 要关闭的文件的描述符</div></li></ul></ul><h2>写入操作</h2><ul><li><div>写入：fs.writeSync(fd, string[, position[, encoding]])</div></li><ul><li><div>fd 文件的描述符，需要传递要写入的文件的描述符</div></li><li><div>string 要写入的内容</div></li><li><div>position 写入的起始位置</div></li><li><div>encoding 写入的编码，默认utf-8</div></li></ul></ul><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">// 加载 fs 模块
const fs = require('fs');

// 打开文件
const fd = fs.openSync(&quot;hello.txt&quot;,&quot;w&quot;);
// 写入内容
fs.writeSync(fd,&quot;今天天气不错~~~&quot;,0);
// 关闭文件
fs.closeSync(fd)
console.log(&quot;程序继续执行&quot;)</div><div><br/></div><h2>读取文件</h2><div style="--en-codeblock:true;--en-codeblockLanguage:text/x-java;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">const fs = require('fs');
let fileStr = fs.readFileSync('C:/桌面/工作文件/北京众杰能科技/项目/外贸信托/脚本/3.sql模板.csv', 'utf8')</div><div><br/></div><div><br/></div><h1>异步操作</h1><ul><li><p>异步文件系统不会阻塞程序的执行，而是在操作完成时，通过回调函数将结果返回。</p></li><li><p>异步操作的方法，都需要给定callback函数</p></li><li><p>打开文件：fs.open(path, flags[, mode], callback)</p></li><ul><li><div>path 要打开文件的路径</div></li><li><div>flags 打开文件要做的操作的类型</div></li><ul><li><div>'w' ：可写的</div></li><li><div>'r'：只读的</div></li><li><div>'a'：追加</div></li></ul><li><div>mode 设置文件的操作权限，一般不传</div></li><li><div>callback 给定回调函数，在打开文件后调用</div></li><ul><li><div>回调函数两个参数：</div></li><ul><li><p>err 错误对象，如果没有错误则为null</p></li><li><p>fd 文件的描述符</p></li></ul></ul><li><div>返回值：该方法会返回一个文件的描述符作为结果，我们可以通过该描述符来对文件进行各种操作</div></li></ul><li><p>关闭文件：fs.close(fd, callback)</p></li><ul><li><p>用来关闭文件</p></li></ul></ul><h2>写入操作</h2><ul><li><p>fs.write(fd, string[, position[, encoding]], callback)</p></li><ul><li><p>用来异步写入一个文件</p></li><li><div>fd 文件的描述符，需要传递要写入的文件的描述符</div></li><li><div>string 要写入的内容</div></li><li><div>position 写入的起始位置</div></li><li><div>encoding 写入的编码，默认utf-8</div></li><li><div>callback 写入完毕后的回调函数</div></li></ul></ul><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">const fs = require('fs')
fs.open('hello.txt','w',(err,fd)=&gt;{
  if(!err){
    // 如果打开成功
    fs.write(fd,&quot;这是异步写入的内容&quot;,(err)=&gt;{
      if(!err){
        // 没有问题
        console.log('写入成功')
      }
      fs.close(fd,err=&gt;{
        if(!err){
          console.log(&quot;文件已关闭！&quot;)
        }
      })
    })
  }else{
    // 文件打开失败
    console.log(&quot;文件打开失败&quot;)
  }
})
console.log(&quot;文件继续运行！&quot;)</div><h2>读取文件</h2><div style="--en-codeblock:true;--en-codeblockLanguage:python;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">fs.readFile('./file/01.txt', 'utf8', function (err, dataStr) {
    if (err) {
        return console.log('读取失败！' + err.message);
    }
    console.log('读取成功!' + dataStr);
})</div><div><br/></div><h1>获取文件信息</h1><ul><li><div>fs.stat(path, callback)</div></li><ul><li><p><b>path</b> - 文件路径。</p></li><li><p><b>callback</b> - 回调函数，带有两个参数如：(err, stats), <b>stats</b> 是 fs.Stats 对象。</p></li><li><div>stats 对象里面放置着信息</div></li></ul></ul><table style="--en-fitwindow:false;border-left:1px solid #d9d9d9;border-top:1px solid #d9d9d9;border-collapse:collapse;width:614px;" width="614px"><colgroup><col style="width: 190px;"></col><col style="width: 424px;"></col></colgroup><tbody><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isFile()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是文件返回 true，否则返回 false。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isDirectory()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是目录返回 true，否则返回 false。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isBlockDevice()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是块设备返回 true，否则返回 false。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isCharacterDevice()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是字符设备返回 true，否则返回 false。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isSymbolicLink()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是软链接返回 true，否则返回 false。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isFIFO()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是FIFO，返回true，否则返回 false。FIFO是UNIX中的一种特殊类型的命令管道。</div></td></tr><tr><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>stats.isSocket()</div></td><td style="--en-typeInfo:{&quot;type&quot;:&quot;text&quot;,&quot;data&quot;:{}};border-right:1px solid #d9d9d9;border-bottom:1px solid #d9d9d9;padding:10px;vertical-align:top;"><div>如果是 Socket 返回 true，否则返回 false。</div></td></tr></tbody></table><ul><li><div>fs.readdir(path,(err,allFiles)=&gt;{})</div></li><ul><li><div>读取给定文件夹下的所有文件名(包括文件夹)</div></li></ul></ul><div style="--en-codeblock:true;--en-codeblockLanguage:clike;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">// 读取文件夹下的所有文件名
fs.readdir(path, (err, allFiles) =&gt; {
  console.log(allFiles)
})</div><div>获取父节点路径</div><div style="--en-codeblock:true;--en-codeblockLanguage:text/x-java;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">parentPath = path.resolve(path_temp,'..')</div><div><br/></div><h1>移动文件</h1><ul><li><div>也可以用于替换名称，fs.rename的第三个参数必须有值，否则会报错</div></li></ul><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">var fs = require('fs');
var path = require('path');

var fileName = &quot;coverflow-3.0.1.zip&quot;;

var sourceFile = path.join(__dirname, fileName);
var destPath = path.join(__dirname, &quot;dest&quot;, fileName);

fs.rename(sourceFile, destPath, function (err) {
  if (err) throw err;
  fs.stat(destPath, function (err, stats) {
    if (err) throw err;
    console.log('stats: ' + JSON.stringify(stats));
  });
});</div><div><br/></div><h1>删除文件</h1><div style="--en-codeblock:true;--en-codeblockLanguage:text/x-java;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">// 删除文件
fs.unlinkSync(curPath);
// 删除文件夹,文件夹下不能有文件
fs.rmdirSync(path);</div><div><br/></div><h2>递归删除文件夹下的所有文件</h2><div style="--en-codeblock:true;--en-codeblockLanguage:text/x-java;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">var fs = require(&quot;fs&quot;); // 引入fs模块

function deleteall(path) {
  var files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function (file, index) {
      let curPath = path + &quot;/&quot; + file;
      if (fs.statSync(curPath).isDirectory()) {
        // recurse
        deleteall(curPath);
      } else {
        // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
}</div><div><br/></div><h1>特殊操作</h1><h2>随机复制/移动一定数量的文件</h2><div><br/></div><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">// 第三方模块
const fs = require('fs')
const path = require('path')
// // 常量
// const path = __dirname + &quot;\\haha&quot;;
// const outPath = __dirname + &quot;\\xixi&quot;;
// const isNeedCopy = false;
// // 选取33%个文件
// const CHOOSE_FILES_LEN = 15
module.exports = {
  /**
   * 复制或者移动指定数量的文件
   * @param {String} srcDirpath 源文件夹路径
   * @param {String} outDirPath 输出文件夹路径
   * @param {boolean} isNeedCopy 是否需要复制
   * @param {Number} CHOOSE_FILES_LEN 选取的文件个数
   */
  moveOrCopyFile: function (srcDirpath, outDirPath, isNeedCopy, CHOOSE_FILES_LEN) {
    new Promise((resovle) =&gt; {
      // 读取文件夹下的所有文件名
      fs.readdir(srcDirpath, (err, allFiles) =&gt; {
        resovle(allFiles)
      })
    }).then(allFiles =&gt; {
      // 找到当前目录下的所有文件名
      files = []
      for (let i = 0; i &lt; allFiles.length; i++) {
        let fileName = allFiles[i]
        let stat = fs.statSync(path.join(srcDirpath, fileName));
        if (stat.isFile()) {
          files.push(fileName)
        }
      }
      if (files.length &gt; 0) {
        return files
      }
      return null;
    }).then(files =&gt; {
      // files 为找到的所有文件
      // 随机选取文件
      // 分析找到的所有文件名
      if (files == null) return null;
      let filesLen = files.length;
      let chooseFilesLen = filesLen &gt; CHOOSE_FILES_LEN ? CHOOSE_FILES_LEN : filesLen;
      // 利用布尔数组来判断文件是否被选择了
      let boolArr = []
      for (let i = 0; i &lt; filesLen; i++) {
        boolArr.push(false)
      }
      // 开始选择
      let chooseFileCount = 0;
      let chooseFiles = []
      while (chooseFileCount &lt; chooseFilesLen) {
        // 得到一个随机数
        let index = Math.floor(Math.random() * (filesLen))
        if (boolArr[index]) continue;
        chooseFiles.push(files[index]);
        boolArr[index] = true;
        ++chooseFileCount;
      }
      // 输出信息
      console.log(&quot;一共&quot; + filesLen.toString() + &quot;个文件&quot; + &quot;,选择了&quot; + chooseFilesLen.toString() + &quot;个文件&quot;)
      console.log(chooseFiles)
      if (chooseFiles.length &gt; 0) return chooseFiles;
      return null;
    }).then(chooseFiles =&gt; {
      if (!isNeedCopy) {
        console.log(&quot;-------------开始移动文件-----------&quot;)
      } else {
        console.log(&quot;-------------开始拷贝文件-----------&quot;)
      }
      // chooseFiles 为选中的文件
      if (chooseFiles == null) return null;
      // 递归创建路径
      fs.mkdirSync(outDirPath, { recursive: true })
      // 复制或者移动文件
      for (let i = 0; i &lt; chooseFiles.length; i++) {
        if (!isNeedCopy) {
          console.log(&quot;正在移动文件：&quot; + chooseFiles[i]);
          // 如果不需要复制，则移动文件
          fs.renameSync(path.join(srcDirpath, chooseFiles[i]), path.join(outDirPath, chooseFiles[i]));
        } else {
          console.log(&quot;正在拷贝文件：&quot; + chooseFiles[i]);
          fs.copyFileSync(path.join(srcDirpath, chooseFiles[i]), path.join(outDirPath, chooseFiles[i]));
        }
      }
      if (!isNeedCopy) {
        console.log(&quot;-------------移动文件结束-----------&quot;)
      } else {
        console.log(&quot;-------------拷贝文件结束-----------&quot;)
      }
    }).catch(e =&gt; {
      console.log(&quot;发生异常了&quot;)
      console.log(e)
    })
  }
}</div><h2>获取文件夹下所有文件的文件全路径</h2><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">// 第三方模块
const fs = require('fs')
const path = require('path')

const dirpath = 'D:\\音乐\\标配'

// 获得所有文件夹名
// @param String filepath: 要遍历的文件路径
// @param Array files: 结果装在该数组中
// @return: files
function getAllFileName(filepath,files){
  let stat = fs.statSync(filepath);
  if(stat.isFile()){
    // 如果是文件，则将文件放置到files数组中
    files.push({
      dirPath: path.dirname(filepath),
      fileName: path.win32.basename(filepath)
    });
    return files;
  }else if(stat.isDirectory()){
    // 如果是文件夹
    let allFiles = fs.readdirSync(filepath);
    for(let i = 0;i&lt;allFiles.length;i++){
      getAllFileName(filepath + '\\' + allFiles[i],files);
    }
    return files;
  }
  return files;
}

let files = [];
getAllFileName(dirpath,files);
console.log(files);</div><div><br/></div><h2>遍历所有文件，并执行相关操作</h2><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">const fs = require(&quot;fs&quot;);
const path = require(&quot;path&quot;);

// 文件夹路径
const dirpath = &quot;D:\\Downloads\\新建文件夹&quot;;



// 只遍历一层,处理返回的文件名
// @param String filepath: 要遍历的文件路径
// @param Function action: 回调处理的函数(dirPath,fileName)=&gt;{}
function getAllFileNameByDir(dirPath, action) {
  let stat = fs.statSync(dirPath);
  if(stat.isDirectory()){
    // 如果是文件夹
    let allFiles = fs.readdirSync(dirPath);
    for (let i = 0; i &lt; allFiles.length; i++) {
      action(dirPath,allFiles[i]);
    }
  }else{
    return;
  }
}

// 递归遍历文件夹，处理返回的文件名
// @param String filepath: 要遍历的文件路径
// @param Function action: 回调处理的函数(dirPath,fileName)=&gt;{}
function getAllFileName(filepath, action) {
  let stat = fs.statSync(filepath);
  if (stat.isFile()) {
    // 将文件夹路径和文件名放置到回调函数中
    action(path.dirname(filepath), path.win32.basename(filepath));
  } else if (stat.isDirectory()) {
    // 如果是文件夹
    let allFiles = fs.readdirSync(filepath);
    for (let i = 0; i &lt; allFiles.length; i++) {
      getAllFileName(path.join(filepath,allFiles[i]),action);
    }
  }
}


getAllFileNameByDir(dirpath, (dirPath, fileName) =&gt; {
  console.log(dirPath), console.log(fileName);
});</div><div><br/></div><h2>隔级空内容文件夹搬运</h2><div>如果A文件夹下只有文件夹B，B文件夹下有其他内容，则会把B文件夹下的所有内容搬运到A文件夹下。</div><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">const fs = require(&quot;fs&quot;);
const path = require(&quot;path&quot;);

// 文件夹路径
const dirpath = &quot;F:\\学习资料\\C++\\opencv&quot;;
// 白名单，不遍历的目录
const whitePath = {
  &quot;F:\\学习资料\\C++\\opencv\\配套代码&quot;:true
}

/**
 * 递归遍历文件夹，处理返回的文件名
 * @param {String} filepath 要遍历的文件路径
 * @param {function} action 回调处理的函数(dirPath,fileName)=&gt;{}
 * @param {boolean} isLastDirEmpty 上一个父节点是否是只有一个文件夹而没有其他东西
 * @param {boolean} isLastLastDirEmpty 上上一个父节点是否是只有一个文件夹而没有其他东西
 */
function getAllFileName(filepath, action, isLastDirEmpty, isLastLastDirEmpty) {
  let stat = fs.statSync(filepath);
  isLastDirEmpty = isLastDirEmpty === undefined ? false : isLastDirEmpty;
  isLastLastDirEmpty =
    isLastLastDirEmpty === undefined ? false : isLastLastDirEmpty;
  if (stat.isFile()) {
    // 将文件夹路径和文件名放置到回调函数中
    action({
      type: &quot;file&quot;,
      dirname: path.dirname(filepath),
      fileName: path.win32.basename(filepath),
      isLastDirEmpty,
      isLastLastDirEmpty,
    });
  } else if (stat.isDirectory()) {
    // 如果是文件夹
    if(whitePath[filepath]===true){
      // 白名单不遍历
      return
    }
    let allFiles = fs.readdirSync(filepath);
    // 如果子文件只有一个并且是文件夹
    isLastLastDirEmpty = isLastDirEmpty;
    isLastDirEmpty =
      allFiles.length === 1 &amp;&amp;
      fs.statSync(path.join(filepath, allFiles[0])).isDirectory();
    for (let i = 0; i &lt; allFiles.length; i++) {
      getAllFileName(
        path.join(filepath, allFiles[i]),
        action,
        isLastDirEmpty,
        isLastLastDirEmpty
      );
    }
    action({
      type: &quot;dir&quot;,
      dirname: path.dirname(filepath),
      fileName: path.win32.basename(filepath),
      isLastDirEmpty,
    });
    if (isLastLastDirEmpty) {
      // 如果需要处理，则要删除这个文件夹
      console.log(`----------删除文件夹:${filepath}`)
      fs.rmdirSync(filepath);
    }
  }
}

// 处理
getAllFileName(dirpath, (ret) =&gt; {
  let { type, dirname, fileName, isLastDirEmpty, isLastLastDirEmpty } = ret;
  console.log(
    `{类型:${type},父节点:${dirname},文件名:${fileName},父节点没内容:${isLastDirEmpty},父父节点没内容:${isLastLastDirEmpty}}`
  );
  if (isLastLastDirEmpty) {
    // 开始搬运
    let srcPath = path.join(dirname, fileName);
    let destPath = path.join(path.resolve(dirname, &quot;..&quot;), fileName);
    console.log(`----------开始搬运:${srcPath}---&gt;${destPath}`);
    fs.renameSync(srcPath, destPath);
  }
});</div><div><br/></div><h2>为文件夹下文件重命名，并搬运出来</h2><div>进入dirpath下的所有文件夹，并给其中文件重命名为 文件夹名 + 文件名，并把文件搬运到dirpath下。</div><div style="--en-codeblock:true;--en-codeblockLanguage:javascript;box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial; margin-top: 6px;">const fs = require(&quot;fs&quot;);
const path = require(&quot;path&quot;);

// 文件夹路径
const dirpath = &quot;&quot;;

// 只遍历一层,处理返回的文件名
// @param String filepath: 要遍历的文件路径
// @param Function action: 回调处理的函数(dirPath,fileName)=&gt;{}
// @param bool isDir: 是否只遍历文件夹
function getAllFileNameByDir(dirPath, action, isDir) {
  let stat = fs.statSync(dirPath);
  if (stat.isDirectory()) {
    // 如果是文件夹
    let allFiles = fs.readdirSync(dirPath);
    for (let i = 0; i &lt; allFiles.length; i++) {
      if (isDir !== undefined &amp;&amp; isDir === true) {
        if (fs.statSync(dirPath + &quot;/&quot; + allFiles[i]).isDirectory()) {
          action(dirPath, allFiles[i]);
        }
      } else {
        action(dirPath, allFiles[i]);
      }
    }
  } else {
    return;
  }
}

getAllFileNameByDir(
  dirpath,
  (dirPath, fileName) =&gt; {
    getAllFileNameByDir(dirPath + &quot;/&quot; + fileName, (dirPath2, fileName2) =&gt; {
      // console.log(`${dirPath2 + &quot;/&quot; + fileName2},${dirPath + &quot;/&quot; + fileName + fileName2}`);
      fs.renameSync(dirPath2 + &quot;/&quot; + fileName2, dirPath + &quot;/&quot; + fileName + fileName2);
    });
  },
  true
);</div><div><br/></div></span>
</div></body></html> 